package com.tiancheng.trade.authserver.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tiancheng.trade.authserver.component.login.UserLoginHandlerFactory;
import com.tiancheng.trade.authserver.constant.SystemConstant;
import com.tiancheng.trade.authserver.entity.AuthApplication;
import com.tiancheng.trade.authserver.enums.LogInTypeEnum;
import com.tiancheng.trade.authserver.enums.ThirdPlatformEnums;
import com.tiancheng.trade.commom.web.auth.OpenAuthTokenConfig;
import com.tiancheng.trade.commom.web.model.SubjectProfile;
import com.tiancheng.trade.authserver.service.AuthLoginService;
import com.tiancheng.trade.authserver.service.IAuthApplicationService;
import com.tiancheng.trade.authserver.service.IAuthTokenService;
import com.tiancheng.trade.authserver.utils.AppAccessTokenSignatureUtils;
import com.tiancheng.trade.authserver.vo.ApplicationAccessTokenRequestVO;
import com.tiancheng.trade.authserver.vo.ApplicationAccessTokenResponseVO;
import com.tiancheng.trade.authserver.vo.UserLoginInVO;
import com.tiancheng.trade.authserver.vo.UserLogInResultVO;
import com.tiancheng.trade.commom.core.exception.AuthorizationException;
import com.tiancheng.trade.commom.web.auth.StpCustomKit;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
 * @Author: likailun
 * @Description:
 * @Date: create in 2024/10/21 15:55
 */
@Slf4j
@Service
public class AuthLoginServiceImpl implements AuthLoginService {

    @Resource
    private UserLoginHandlerFactory userLoginHandlerFactory;
    @Resource
    private IAuthApplicationService applicationService;
    @Resource
    protected IAuthTokenService authTokenService;
    @Resource
    private OpenAuthTokenConfig openAuthTokenConfig;

    @Override
    public UserLogInResultVO userSignIn(UserLoginInVO param, boolean checkCertificate) {
        LogInTypeEnum logInTypeEnum = LogInTypeEnum.SmsCode;
        if (StringUtils.isNotEmpty(param.getPassword())) {
            logInTypeEnum = LogInTypeEnum.Password;
        }
        if (param.getThirdPlatform() != null && param.getThirdPlatform() == ThirdPlatformEnums.wechat_miniapp) {
            logInTypeEnum = LogInTypeEnum.WeChatMiniApp;
        }

        return userLoginHandlerFactory.getHandler(logInTypeEnum).signIn(param, false);
    }

    @Override
    public ApplicationAccessTokenResponseVO getAccessToken(ApplicationAccessTokenRequestVO param) {
        long timestampSub = Math.abs(System.currentTimeMillis() - param.getTimestamp());
        Assert.isTrue(timestampSub < 60000, "invalid timestamp");
        AuthApplication application = this.applicationService.getOne(new LambdaQueryWrapper<AuthApplication>().eq(AuthApplication::getClientId, param.getClientId()));
        Assert.isTrue(null != application && Objects.nonNull(application.getId()), "invalid clientId");
        String signature = AppAccessTokenSignatureUtils.signature(param.getClientId(), param.getRand(), param.getTimestamp().toString(), application.getClientSecret());
        if (!signature.equals(param.getSignature())) {
            throw new AuthorizationException(401, "invalid signature");
        }
        SubjectProfile commonProfile = new SubjectProfile();
        commonProfile.setId(application.getId());
        commonProfile.addAttribute("name", application.getName());
        commonProfile.addAttribute("clientId", application.getClientId());
        commonProfile.addAttribute("clientSecret", application.getClientSecret());
        commonProfile.addAttribute("expiresIn", SystemConstant.applicationTokenTimeout);
        ApplicationAccessTokenResponseVO result = new ApplicationAccessTokenResponseVO();

        /*String tokenStr = this.authTokenService.generate(TokenTypeEnum.application,
                SystemConstant.applicationTokenTimeout, ThirdPlatformEnums.tiancheng,
                param.getClientId(), commonProfile, null);
*/
        // SaLoginModel 配置登录相关参数
        StpCustomKit.OPEN.login(application.getId(), new SaLoginModel().setDevice("PC")                // 此次登录的客户端设备类型, 用于[同端互斥登录]时指定此次登录的设备类型
                .setIsLastingCookie(true)        // 是否为持久Cookie（临时Cookie在浏览器关闭时会自动删除，持久Cookie在重新打开后依然存在）
                .setExtra("application", commonProfile)    // Token挂载的扩展参数 （此方法只有在集成jwt插件时才会生效）
                .setIsWriteHeader(true)         // 是否在登录后将 Token 写入到响应头
                .setTimeout(openAuthTokenConfig.getOpenApiTokenConfig().getTimeout()));
        final SaTokenInfo tokenInfo = StpCustomKit.OPEN.getTokenInfo();
        result.setAccessToken(tokenInfo.getTokenValue());
        result.setExpiresIn(Long.valueOf(openAuthTokenConfig.getOpenApiTokenConfig().getTimeout()));
        return result;
    }
}
